package com.jw.debezuim.config.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.jw.debezuim.common.dto.LoginUserDto;
import com.jw.debezuim.common.dto.Result;
import com.jw.debezuim.config.context.TC;
import com.jw.debezuim.utils.JwtHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.SameSiteCookies;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.time.Duration;

@Component
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {

    public final static String USER_TOKEN_HEAD = "user-token";
    @Value("${biz.security.login-url:}")
    private String loginUrl;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //设置返回JSON数据
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;

        String token = null;
//        String token = request.getHeader(USER_TOKEN_HEAD);
//        log.info("当前登录用户[{} = {}]", USER_TOKEN_HEAD, token);
        if (StringUtils.isEmpty(token) && request.getCookies() != null && request.getCookies().length > 0) {
            for (Cookie cookie : request.getCookies()) {
                if (USER_TOKEN_HEAD.equals(cookie.getName())) {
                    token = cookie.getValue();
                    log.info("当前登录用户cookie[{} = {}]", USER_TOKEN_HEAD, token);
                    break;
                }
            }
        }

        if (StringUtils.isEmpty(token)) {
            Result<Object> fail = Result.fail(HttpStatus.FORBIDDEN);
            out = response.getWriter();
            out.append(JSONObject.toJSONString(fail));
//            redirectLoginPage(this.loginUrl, request, response);
            return false;
        }
        try {
            DecodedJWT jwt = JwtHelper.verifyToken(token);
            LoginUserDto loginUserDto = JwtHelper.getUserInfo(jwt);
            log.info("解析用户[{} = {} ]", USER_TOKEN_HEAD, loginUserDto);
            TC.setUserInfo(loginUserDto);
            TC.setJwt(jwt);
            //token续命
            if (JwtHelper.needExpiresExtension(jwt)) {
                String newToken = JwtHelper.createToken(loginUserDto);
                ResponseCookie cookie = ResponseCookie.from(AuthenticationInterceptor.USER_TOKEN_HEAD, newToken)
                        // 禁止js读取
                        .httpOnly(false)
                        // 在http下也传输
                        .secure(false)
                        // path
                        .path("/")
                        // 过期
                        .maxAge(Duration.ofDays(7))
                        // 大多数情况也是不发送第三方 Cookie，但是导航到目标网址的 Get 请求除外
                        .sameSite(SameSiteCookies.LAX.getValue())
                        .build();
                response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
            }

            return true;
        } catch (Exception e) {
            log.warn("拦截token异常捕获", e);
            Result<Object> fail = Result.fail(HttpStatus.FORBIDDEN);
            out = response.getWriter();
            out.append(JSONObject.toJSONString(fail));
//            redirectLoginPage(this.loginUrl, request, response);
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
//        DecodedJWT jwt = TC.getJwt();
//        LoginUserDto userInfo = TC.getUserInfo();
        TC.remove();
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }

    public static void redirectLoginPage(String loginUrl, HttpServletRequest request, HttpServletResponse response) throws IOException {
        StringBuffer requestURL = request.getRequestURL();
        requestURL.setLength(requestURL.length() - request.getRequestURI().length());
        requestURL.append("/ivr/user/login/callback");
        loginUrl = String.format(loginUrl, URLEncoder.encode(requestURL.toString(), "utf-8"));
        response.sendRedirect(loginUrl);
    }

}
